/**
 * useStreamFetch.ts
 * 
 * 统一AI流式请求处理钩子，支持多种AI平台集成
 * 
 * 本模块提供了一个统一的接口来处理与不同AI平台的流式对话交互，
 * 包括火山平台、Dify平台和自定义平台。它处理消息的发送、流式接收、
 * 解析和状态管理，同时支持思考模式、上下文管理等高级功能。
 * 
 * @author Your Name
 * @date 2023-XX-XX
 */
import { ref, watch } from 'vue'
import { 
  volcanoBodyBuilder, 
  volcanoParseMessage,
  volcanoConfig,
  useVolcanoChat as _useVolcanoChat
} from './platforms/volcano';
import {
  difyBodyBuilder,
  difyParseMessage,
  difyConfig,
  useDifyChat as _useDifyChat
} from './platforms/dify';

/**
 * 支持的AI模型类型枚举
 * 定义系统支持的各种AI模型类型
 */
export enum AIModelType {
  /** Deepseek AI模型 */
  DEEPSEEK = 'deepseek-v3-250324',
  /** GPT-4模型 */
  GPT_4 = 'gpt-4',
  /** GPT-3.5 Turbo模型 */
  GPT_3_5 = 'gpt-3.5-turbo',
  /** 自定义模型类型 */
  CUSTOM = 'custom'
}

/**
 * 支持的平台类型枚举
 * 定义系统支持的AI服务平台类型
 */
export enum PlatformType {
  /** 火山引擎AI平台 */
  VOLCANO = 'volcano', 
  /** Dify AI平台 */
  DIFY = 'dify',       
  /** 自定义平台，允许用户自行配置 */
  CUSTOM = 'custom'    
}

/**
 * 请求体构建函数类型
 * 根据消息列表和配置构建平台特定的请求体
 */
export interface BuildBodyFunction {
  /**
   * @param messages - 消息列表
   * @param config - 流式请求配置
   * @returns 构建好的请求体对象
   */
  (messages: Message[], config: StreamFetchConfig): any;
}

/**
 * 平台预设配置接口
 * 定义平台交互所需的基础配置
 */
export interface PlatformPreset {
  /** API基础URL */
  baseUrl: string;
  /** 请求头配置 */
  headers?: Record<string, string>;
  /** 消息解析函数 */
  parseFunction?: ParseFunction;
  /** 请求体构建函数 */
  buildBodyFunction?: BuildBodyFunction;
}

/**
 * 平台配置映射
 * 将平台类型映射到对应的预设配置
 */
const PLATFORM_PRESETS: Record<string, PlatformPreset> = {
  [PlatformType.VOLCANO]: volcanoConfig as PlatformPreset,
  [PlatformType.DIFY]: difyConfig as PlatformPreset,
  [PlatformType.CUSTOM]: {
    baseUrl: '',
  }
};

/**
 * 消息类型接口
 * 定义AI对话中的消息格式
 */
export interface Message {
  /** 消息角色: 'system'(系统),'user'(用户),'assistant'(助手) */
  role: 'system' | 'user' | 'assistant';
  /** 消息内容 */
  content: string;
}

/**
 * 流式请求选项接口
 * 定义构建HTTP请求需要的选项
 */
export interface StreamRequestOptions {
  /** HTTP方法，通常为POST */
  method: string;
  /** HTTP请求头 */
  headers: Record<string, string>;
  /** 请求体，通常为JSON字符串 */
  body?: string;
}

/**
 * 解析函数类型
 * 将服务器响应的消息解析为文本
 */
export interface ParseFunction {
  /**
   * @param message - 服务器响应的原始消息
   * @returns 解析后的文本内容，解析失败时返回null
   */
  (message: string): string | null;
}

/**
 * 思考内容解析函数类型
 * 从响应内容中提取思考内容
 */
export interface ThinkParseFunction {
  /**
   * @param content - 响应内容
   * @returns 提取的思考内容，提取失败时返回null
   */
  (content: string): string | null;
}

/**
 * AI流式请求详细配置选项
 * 定义创建AI流式对话所需的完整配置
 */
export interface AIStreamOptions {
  // 基本配置
  /** 平台类型 */
  platform: PlatformType;                  
  /** AI模型，可以是预定义模型或自定义字符串 */
  model?: string | AIModelType;            
  /** 认证令牌 */
  authToken: string;                       

  // 自定义项
  /** 自定义基础URL，覆盖平台默认值 */
  baseUrl?: string;                        
  /** 自定义请求头 */
  customHeaders?: Record<string, string>;  
  /** 自定义解析函数 */
  parseMessage?: ParseFunction;            
  /** 自定义请求体构建函数 */
  buildBody?: BuildBodyFunction;           

  // 思考模式
  /** 是否是思考模型，启用后将解析思考标签内容 */
  isThinking?: boolean;                    
  /** 思考开始标签，默认 <think> */
  thinkStartTag?: string;                  
  /** 思考结束标签，默认 </think> */
  thinkEndTag?: string;                    

  // 上下文控制
  /** 是否启用上下文，默认true */
  enableContext?: boolean;                 
  /** 最大上下文消息数，默认10 */
  maxContextMessages?: number;             

  // 调试选项
  /** 是否启用调试模式 */
  debug?: boolean;                         
}

/**
 * 默认消息解析器
 * 尝试解析标准SSE消息格式的内容
 * 
 * @param message - 服务器发送的事件消息
 * @returns 解析后的文本内容，解析失败时返回null
 */
const defaultParseMessage: ParseFunction = (message: string): string | null => {
  if (!message.startsWith('data:')) return null;
  const dataStr = message.slice(5).trim();
  try {
    const parsedData = JSON.parse(dataStr);
    // 默认处理逻辑，可以根据需要修改或扩展
    if ('choices' in parsedData && parsedData.choices[0].delta.content) {
      return parsedData.choices[0].delta.content;
    } else if ('answer' in parsedData) {
      return parsedData.answer;
    }
    return null;
  } catch (e) {
    console.warn('无法解析的消息内容:', dataStr);
    return null;
  }
};

/**
 * 默认思考内容解析器
 * 从内容中提取<think>标签包裹的思考内容
 * 
 * @param content - 响应内容
 * @returns 提取的思考内容，提取失败时返回null
 */
const defaultThinkParser: ThinkParseFunction = (content: string): string | null => {
  // 检查内容是否包含思考内容 <think> 标签
  const thinkMatch = content.match(/<think>([\s\S]*?)<\/think>/);
  if (thinkMatch && thinkMatch[1]) {
    return thinkMatch[1].trim();
  }
  return null;
};

/**
 * 默认请求体构建函数
 * 构建标准的流式对话请求体
 * 
 * @param messages - 消息列表
 * @param config - 配置对象
 * @returns 构建好的请求体对象
 */
const defaultBodyBuilder: BuildBodyFunction = (messages, config) => {
  return {
    model: config.model || AIModelType.DEEPSEEK,
    stream: true,
    messages
  };
};

/**
 * 简化的流式请求配置选项
 * 定义实际发起流式请求所需的必要配置
 */
export interface StreamFetchConfig {
  /** API 端点 URL */
  url: string;
  /** 授权令牌 */
  authToken?: string;
  /** 平台类型 */
  platform?: PlatformType;
  /** AI 模型 */
  model?: AIModelType | string;
  /** 自定义请求头 */
  customHeaders?: Record<string, string>;
  /** 自定义解析函数 */
  parseMessage?: ParseFunction;
  /** 自定义请求体构建函数 */
  buildBody?: BuildBodyFunction;
  /** 是否是思考模型 */
  isThinking?: boolean;
  /** 思考开始标签 */
  thinkStartTag?: string;
  /** 思考结束标签 */
  thinkEndTag?: string;
}

/**
 * 获取平台对应的解析函数
 * 
 * @param platform - 平台类型
 * @returns 适用于指定平台的消息解析函数
 */
const getPlatformParser = (platform: PlatformType): ParseFunction => {
  const preset = PLATFORM_PRESETS[platform];
  if (preset && preset.parseFunction) {
    return preset.parseFunction;
  }

  switch (platform) {
    case PlatformType.VOLCANO:
      return volcanoParseMessage;
    case PlatformType.DIFY:
      return difyParseMessage;
    default:
      return defaultParseMessage;
  }
};

/**
 * 获取平台对应的请求体构建函数
 * 
 * @param platform - 平台类型
 * @returns 适用于指定平台的请求体构建函数
 */
const getPlatformBodyBuilder = (platform: PlatformType): BuildBodyFunction => {
  const preset = PLATFORM_PRESETS[platform];
  if (preset && preset.buildBodyFunction) {
    return preset.buildBodyFunction;
  }

  switch (platform) {
    case PlatformType.VOLCANO:
      return volcanoBodyBuilder;
    case PlatformType.DIFY:
      return difyBodyBuilder;
    default:
      return defaultBodyBuilder;
  }
};

/**
 * 构建请求选项
 * 根据消息和配置构建HTTP请求选项
 *
 * @param messages - 消息列表
 * @param config - 流式请求配置
 * @returns 构建好的HTTP请求选项
 */
const buildRequestOptions = (
  messages: Message[],
  config: StreamFetchConfig
): StreamRequestOptions => {
  // 默认请求头
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...config.customHeaders || {}
  };

  // 添加授权头
  if (config.authToken) {
    headers.Authorization = `Bearer ${config.authToken}`;
  }

  // 获取请求体构建函数
  const bodyBuilder = config.buildBody ||
                      (config.platform ? getPlatformBodyBuilder(config.platform) : defaultBodyBuilder);

  // 构建请求体
  const bodyContent = bodyBuilder(messages, config);
  const body = JSON.stringify(bodyContent);

  return {
    method: 'POST',
    headers,
    body
  };
};

/**
 * 构建AI流式请求配置
 * 根据用户选项构建完整的流式请求配置
 * 
 * @param options - AI流式请求选项
 * @returns 构建好的流式请求配置
 */
function buildAIStreamConfig(options: AIStreamOptions): StreamFetchConfig {
  const platformPreset = PLATFORM_PRESETS[options.platform];

  // 基础URL
  const url = options.baseUrl || platformPreset.baseUrl;

  // 解析函数
  const parseMessage = options.parseMessage || 
                      (platformPreset.parseFunction ? platformPreset.parseFunction : getPlatformParser(options.platform));

  // 请求体构建函数
  const buildBody = options.buildBody || 
                   (platformPreset.buildBodyFunction ? platformPreset.buildBodyFunction : getPlatformBodyBuilder(options.platform));

  // 自定义头
  const customHeaders = {
    ...(platformPreset.headers || {}),
    ...(options.customHeaders || {})
  };

  return {
    url,
    authToken: options.authToken,
    platform: options.platform,
    model: options.model,
    customHeaders,
    parseMessage,
    buildBody,
    isThinking: options.isThinking || false,
    thinkStartTag: options.thinkStartTag || '<think>',
    thinkEndTag: options.thinkEndTag || '</think>'
  };
}

/**
 * 统一AI流式对话钩子
 * 主要入口函数，创建一个流式AI对话实例
 * 
 * @param options - AI流式请求选项
 * @returns 包含流式对话状态和方法的对象
 * @throws Error 当未提供必要参数时
 */
export function useAIStream(options: AIStreamOptions) {
  if (!options.platform) {
    throw new Error('必须指定AI平台类型');
  }

  if (!options.authToken) {
    throw new Error('必须提供认证令牌');
  }

  // 构建配置
  const config = buildAIStreamConfig(options);

  // 基础变量
  const data = ref('')
  const thinkData = ref('') // 思考内容数据
  const isLoading = ref(false)
  const error = ref<Error | null>(null)
  const currentController = ref<AbortController | null>(null)

  // 思考模式状态管理
  const isCollectingThinking = ref(false) // 是否正在收集思考内容

  // 聊天历史
  const chatHistory = ref<Message[]>([]);

  // 最后一条消息
  const lastMessage = ref<string>('');

  // 是否保留上下文
  const keepContext = ref<boolean>(options.enableContext !== false);

  // 最大上下文消息数
  const maxContextMessages = ref<number>(options.maxContextMessages || 10);

  // 调试模式
  const debug = options.debug === true;

  /**
   * 获取上下文消息
   * 根据设置的最大上下文消息数获取聊天历史
   * 
   * @returns 上下文消息数组
   */
  const getContextMessages = () => {
    if (!keepContext.value) {
      return [];
    }

    return chatHistory.value.slice(-maxContextMessages.value);
  };

  /**
   * 执行流式请求
   * 发起流式HTTP请求并处理响应数据流
   * 
   * @param url - 请求URL
   * @param requestOptions - 请求选项
   */
  const executeFetch = async (url: string, requestOptions: StreamRequestOptions) => {
    data.value = ''
    thinkData.value = '' // 重置思考数据
    isCollectingThinking.value = false // 重置思考收集状态
    error.value = null
    isLoading.value = true

    currentController.value = new AbortController()
    const { signal } = currentController.value

    let reader: ReadableStreamDefaultReader | null = null
    const decoder = new TextDecoder('utf-8')
    let buffer = ''

    try {
      if (debug) {
        console.log("发送请求到:", url, "配置:", {
          method: requestOptions.method,
          headers: requestOptions.headers,
          body: requestOptions.body ? JSON.parse(requestOptions.body) : null
        });
      }

      const response = await fetch(url, {
        ...requestOptions,
        signal,
      })

      if (!response.ok) {
        const errorText = await response.text().catch(() => '无法获取错误详情');
        throw new Error(`HTTP错误: ${response.status}, ${errorText}`);
      }

      if (!response.body) throw new Error('响应中没有 body')

      reader = response.body.getReader()

      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        const chunk = decoder.decode(value, { stream: true });
        if (debug) {
          console.log("收到数据块:", chunk);
        }

        buffer += chunk;

        // 根据平台类型使用不同的分隔方式
        let messages: string[] = [];
        if (config.platform === PlatformType.VOLCANO) {
          // 火山平台的响应格式
          messages = buffer.split(/\n\n(?=data:)/);
        } else if (config.platform === PlatformType.DIFY) {
          // Dify平台的响应格式
          messages = buffer.split(/\n/);
        } else {
          // 默认分隔方式
          messages = buffer.split(/\n\n/);
        }

        buffer = messages.pop() || '';

        for (const msg of messages) {
          if (!msg.trim()) continue;

          const parsedContent = config.parseMessage ? config.parseMessage(msg.trim()) : null;
          if (parsedContent) {
            if (config.isThinking) {
              // 处理思考内容
              processThinkingContent(parsedContent);
            } else {
              // 非思考模式，直接添加内容
              data.value += parsedContent;
            }
          } else if (debug) {
            console.warn("无法解析的消息:", msg);
          }
        }
      }
    } catch (err) {
      if ((err as Error).name !== 'AbortError') {
        error.value = err as Error;
        console.error('流式请求出错:', err);
      }
    } finally {
      isLoading.value = false;
      currentController.value = null;
      if (reader) await reader.releaseLock();
    }
  };

  /**
   * 处理思考内容
   * 解析响应中的思考内容标签，分离普通回复和思考内容
   * 
   * @param content - 原始响应内容
   */
  const processThinkingContent = (content: string) => {
    const startTag = config.thinkStartTag || '<think>';
    const endTag = config.thinkEndTag || '</think>';

    if (!isCollectingThinking.value) {
      // 如果尚未开始收集思考内容，检查是否包含开始标记
      const startIndex = content.indexOf(startTag);
      if (startIndex !== -1) {
        // 找到开始标记，开始收集思考内容
        isCollectingThinking.value = true;
        // 添加开始标记之后的内容
        thinkData.value += content.slice(startIndex + startTag.length);

        // 检查同一内容中是否也包含结束标记
        const endIndex = content.indexOf(endTag);
        if (endIndex !== -1) {
          // 找到结束标记，停止收集思考内容
          isCollectingThinking.value = false;
          // 添加结束标记之前的内容
          thinkData.value = thinkData.value.slice(0, thinkData.value.length - (content.length - endIndex));
          // 添加结束标记之后的内容到正常数据
          data.value += content.slice(endIndex + endTag.length);
        }
      } else {
        // 没有开始标记，添加到正常数据
        data.value += content;
      }
    } else {
      // 已经开始收集思考内容，检查是否包含结束标记
      const endIndex = content.indexOf(endTag);
      if (endIndex !== -1) {
        // 找到结束标记，停止收集思考内容
        isCollectingThinking.value = false;
        // 添加结束标记之前的内容到思考数据
        thinkData.value += content.slice(0, endIndex);
        // 添加结束标记之后的内容到正常数据
        data.value += content.slice(endIndex + endTag.length);
      } else {
        // 没有结束标记，继续收集思考内容
        thinkData.value += content;
      }
    }
  };

  /**
   * 中止请求
   * 取消正在进行的流式请求
   */
  const abortFetch = () => {
    if (currentController.value) {
      currentController.value.abort()
      currentController.value = null
    }
  };

  /**
   * 发送消息获取AI回复
   * 主要对话方法，发送用户消息并获取AI响应
   * 
   * @param userMessage - 用户消息内容
   * @param systemPrompt - 可选的系统提示消息
   * @returns AI回复的内容
   */
  const chat = async (userMessage: string, systemPrompt?: string) => {
    // 添加用户消息到历史
    const userMsg: Message = {
      role: 'user',
      content: userMessage
    };

    chatHistory.value.push(userMsg);

    // 构建消息数组
    const messages: Message[] = [];

    // 添加系统提示
    if (systemPrompt) {
      messages.push({
        role: 'system',
        content: systemPrompt
      });
    }

    // 添加上下文消息
    if (keepContext.value) {
      const contextMessages = getContextMessages();
      messages.push(...contextMessages);
    }

    // 添加用户消息
    messages.push(userMsg);

    // 构建请求选项
    const requestOptions = buildRequestOptions(messages, config);

    // 重置最后一条消息
    lastMessage.value = '';

    // 开始请求
    await executeFetch(config.url, requestOptions);

    // 添加 AI 回复到历史
    if (data.value) {
      chatHistory.value.push({
        role: 'assistant',
        content: data.value
      });

      // 设置最后一条消息
      lastMessage.value = data.value;
    }

    return data.value;
  };

  /**
   * 清空聊天历史
   * 重置聊天历史和最后一条消息
   */
  const clearHistory = () => {
    chatHistory.value = [];
    lastMessage.value = '';
  };

  /**
   * 设置上下文保留状态
   * 控制是否在对话中保留之前的上下文
   * 
   * @param value - 是否保留上下文
   */
  const setKeepContext = (value: boolean) => {
    keepContext.value = value;
    if (!value) {
      clearHistory();
    }
  };

  /**
   * 设置最大上下文消息数
   * 控制在对话中保留的最大历史消息数量
   * 
   * @param value - 最大保留的消息数
   */
  const setMaxContextMessages = (value: number) => {
    maxContextMessages.value = value;
  };

  return {
    data,
    thinkData, // 返回思考数据
    isLoading,
    error,
    chat,
    abortFetch,
    chatHistory,
    lastMessage,
    keepContext,
    maxContextMessages,
    clearHistory,
    setKeepContext,
    setMaxContextMessages,
    getContextMessages
  };
}

/**
 * 原始的useStreamFetch钩子
 * 用于一般流式请求的简化版本，保留原有功能
 * 
 * @param url - API端点URL
 * @param requestOptions - 请求选项
 * @param parseMessage - 可选的自定义解析函数
 * @returns 包含流式请求状态和方法的对象
 */
export const useStreamFetch = (
  url: string,
  requestOptions: StreamRequestOptions,
  parseMessage: ParseFunction = defaultParseMessage
) => {
  const data = ref('')
  const isLoading = ref(false)
  const error = ref<Error | null>(null)
  let currentController: AbortController | null = null

  /**
   * 开始流式请求
   * 发起请求并处理响应数据流
   */
  const startFetch = async () => {
    data.value = ''
    error.value = null
    isLoading.value = true

    currentController = new AbortController()
    const { signal } = currentController

    let reader: ReadableStreamDefaultReader | null = null
    const decoder = new TextDecoder('utf-8')
    let buffer = ''

    try {
      const response = await fetch(url, {
        ...requestOptions,
        signal,
      })

      if (!response.ok) throw new Error(`HTTP错误: ${response.status}`)
      if (!response.body) throw new Error('响应中没有 body')

      reader = response.body.getReader()

      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        buffer += decoder.decode(value, { stream: true })
        const messages = buffer.split(/\n\n(?=data:)/)
        buffer = messages.pop() || ''

        for (const msg of messages) {
          const parsedContent = parseMessage(msg.trim())
          if (parsedContent) {
            data.value += parsedContent
          }
        }
      }
    } catch (err) {
      if ((err as Error).name !== 'AbortError') {
        error.value = err as Error
        console.error('流式请求出错:', err)
      }
    } finally {
      isLoading.value = false
      currentController = null
      if (reader) await reader.releaseLock()
    }
  }

  /**
   * 中止流式请求
   * 取消正在进行的请求
   */
  const abortFetch = () => {
    if (currentController) {
      currentController.abort()
      currentController = null
    }
  }

  return {
    data,
    isLoading,
    error,
    startFetch,
    abortFetch,
  }
}

/**
 * 火山平台快速集成钩子
 * 提供便捷的火山平台对话接口
 * 
 * @param authToken - 认证令牌
 * @param model - AI模型名称，默认为DEEPSEEK
 * @returns 包含流式对话状态和方法的对象
 */
export const useVolcanoChat = (authToken: string, model: AIModelType | string = AIModelType.DEEPSEEK) => {
  const config = _useVolcanoChat(authToken, model);
  return useAIStream({
    ...config,
    platform: PlatformType.VOLCANO
  });
};

/**
 * Dify平台快速集成钩子
 * 提供便捷的Dify平台对话接口
 * 
 * @param url - Dify API 端点
 * @param authToken - 认证令牌
 * @param isThinking - 是否启用思考模式，默认为false
 * @returns 包含流式对话状态和方法的对象
 */
export const useDifyChat = (url: string, authToken: string, isThinking: boolean = false) => {
  const config = _useDifyChat(url, authToken, isThinking);
  return useAIStream({
    ...config,
    platform: PlatformType.DIFY
  });
};
